# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Vulnerabilities::StarboardVulnerabilityResolveService, feature_category: :vulnerability_management do
  let_it_be(:agent) { create(:cluster_agent) }
  let_it_be(:other_agent) { create(:cluster_agent) }
  let_it_be(:project) { agent.project }
  let_it_be(:user) { agent.created_by_user }

  let_it_be(:existing_vulnerabilities) do
    create_list(:vulnerability, 4,
      :detected, :with_cluster_image_scanning_finding,
      agent_id: agent.id.to_s, project: project, report_type: :cluster_image_scanning
    )
  end

  let_it_be(:detected_vulnerabilities) { existing_vulnerabilities.first(2) }
  let_it_be(:undetected_vulnerabilities) { existing_vulnerabilities - detected_vulnerabilities }
  let_it_be(:uuids) { detected_vulnerabilities.map(&:finding).map(&:uuid) }

  let(:service) { described_class.new(agent, uuids) }

  describe "#new" do
    specify { expect(service.author).to be(user) }
    specify { expect(service.project).to be(project) }
    specify { expect(service.uuids).to eq(uuids) }
  end

  describe "#execute" do
    context 'with authorized user' do
      before_all do
        project.add_developer(user)
      end

      context 'with feature enabled' do
        before do
          stub_licensed_features(security_dashboard: true)
        end

        it 'resolves vulnerabilities' do
          service.execute

          expect(Vulnerability.resolved).to match_array(undetected_vulnerabilities)
        end

        it 'marks vulnerabilities as resolved on default branch' do
          service.execute

          expect(Vulnerability.with_resolution).to match_array(undetected_vulnerabilities)
        end

        it 'does not resolve vulnerabilities with other report types' do
          Vulnerability.where(id: undetected_vulnerabilities).update_all(report_type: :container_scanning)

          expect { service.execute }.not_to change { Vulnerability.resolved.count }
        end

        it "does not resolve other projects' vulnerabilities" do
          Vulnerability.where(id: undetected_vulnerabilities).update_all(project_id: create(:project).id)

          expect { service.execute }.not_to change { Vulnerability.resolved.count }
        end

        it "does not resolve vulnerabilities created by other agent" do
          Vulnerabilities::Finding.all.each do |finding|
            finding.location['kubernetes_resource']['agent_id'] = other_agent.id.to_s
            finding.save!
          end

          expect { service.execute }.not_to change { Vulnerability.resolved.count }
        end

        it 'does not resolve vulnerabilities in passive states' do
          EE::Vulnerability::PASSIVE_STATES.each do |state|
            Vulnerability.where(id: undetected_vulnerabilities).update_all(state: state)

            expect { service.execute }.not_to change { Vulnerability.resolved.count }
          end
        end
      end

      context 'with feature disabled' do
        before do
          stub_licensed_features(security_dashboard: false)
        end

        it 'raises AccessDeniedError' do
          expect { service.execute }.to raise_error(Gitlab::Access::AccessDeniedError)
        end
      end
    end

    context 'with unauthorized user' do
      before_all do
        project.add_reporter(user)
      end

      it 'raises AccessDeniedError' do
        expect { service.execute }.to raise_error(Gitlab::Access::AccessDeniedError)
      end
    end
  end
end
